package com.ouc.pampas;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.Maps;
import com.ouc.openplatform.pampas.Agent;
import com.ouc.openplatform.pampas.ParamUtil;
import com.ouc.openplatform.pampas.UserUtil;
import com.ouc.openplatform.pampas.WrapResp;
import io.terminus.pampas.engine.mapping.ParamConverter;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class DubboExecutor
  extends Executor<Object>
{
  @Autowired
  private DubboHelper dubboHelper;
  private LoadingCache<Service, LinkedHashMap<String, Class>> methodInfoCache;
  
  @PostConstruct
  private void init()
  {
    this.methodInfoCache = CacheBuilder.newBuilder().build(new CacheLoader()
    {
	@Override
	public Object load(Object service) throws Exception {
		  Agent agent = DubboExecutor.this.getAgent(((Service) service).getApp());
	        LinkedHashMap<String, String> paramsInfo = agent.getParamsInfo(((Service) service).getUri());
	        LinkedHashMap<String, Class> params = Maps.newLinkedHashMap();
	        for (String name : paramsInfo.keySet())
	        {
	          String className = (String)paramsInfo.get(name);
	          Class paramClass = ParamUtil.getPrimitiveClass(className);
	          if (paramClass == null) {
	            try
	            {
	              paramClass = Class.forName(className);
	            }
	            catch (ClassNotFoundException e)
	            {
	              paramClass = ParamConverter.UnKnowClass.class;
	            }
	          }
	          params.put(name, paramClass);
	        }
	        return params;
	}
    });
  }
  
  public Object exec(Service service, Map<String, Object> params)
  {
    LinkedHashMap<String, Class> methodParams = (LinkedHashMap)this.methodInfoCache.getUnchecked(service);
    Map<String, Object> args = Maps.newHashMap();
    boolean needContext = false;
    for (String paramName : methodParams.keySet())
    {
      Class paramClass = (Class)methodParams.get(paramName);
      Object arg = ParamConverter.convertParam(paramName, paramClass, params);
      if (arg != null) {
        args.put(paramName, arg);
      } else if (!ParamUtil.isPrimitive(paramClass)) {
        needContext = true;
      }
    }
    Agent agent = getAgent(service.getApp());
    WrapResp wrapResp = agent.call(service.getUri(), args, needContext ? params : null, UserUtil.getCurrentUser());
    if (wrapResp.getCookie() != null) {
      UserUtil.getInnerCookie().merge(wrapResp.getCookie());
    }
    return unwrapResponse(wrapResp.getResult());
  }
  
  private Agent getAgent(String app)
  {
    return (Agent)this.dubboHelper.getReference(Agent.class, app);
  }
}
